Recent Changes - Search:

Home & News

Organization

Assignments

Support

edit SideBar

Lab1

General Remarks

  • Group work is NOT allowed in the lab. You have to work alone. Discussions with colleagues (e.g., in the forum) are allowed but the code has to be written alone.
  • The assignment contains three parts: a chat client/server implementation, an implementation of a direct connection between clients, and a test client. We suggest you implement one after another.
  • Be sure to check the Tricky Parts section for questions!
  • Further reading is provided under tutorials

Submission Guide (for all Labs)

  • You must upload your solution using the Teaching Tool before the submission deadline: 05.11.2007, 13:00.
  • Before the submission deadline, you can upload your solution as often as you like.
  • After the submission deadline, there will be a mandatory interview (Abgabegespräch). You must register for a time slot to the interviews using the Teaching Tool.
  • The interview will take place in our lab. During the interview, you will be asked about the solution that you have uploaded (changes after the deadline will not be taken into account!). In the interview you need to explain your code, design and architecture in detail.
  • You may pass the interviews beginning two weeks before the main "interview" - week. You need to submit your solution to the teaching tool and explain your assignment during a tutor interview. Benefit: Faster passing of lab 1. Drawback: Less time to code ;)
  • Remember that you can do the interview only once!
  • Your submission must compile and run in our lab environment. Please test before you submit. Please provide ant-tasks to ease testing. You may use our ant template.
  • Please upload as a ZIP file. Please submit only the sources of your solution (not the compiled class files). Do not use or include third-party libraries.

Description

In this assignment you will learn:

  • the basics of socket communication
  • how to program multithreaded
  • different connection types

In this year's DSLAB you will develop a fancy socket based chat system. You need to implement two components:

Client The client connects to the server to announce chat availability. It accepts simple console Input and sends the message to the server. Beyond simple messaging functionality, clients are able to search for currently connected clients and establish chats exclusively (on separate connections) with other clients. We call this feature Direct Chat.
Server The server accepts client connections and executes client queries. To simplify matters the server runs in an infinite loop. To end the server you simply kill the executing jobs (for Details please refer to Server)

Sockets
Most interprocess communication uses the client server model. These terms refer to the two processes which will be communicating with each other. One of the two processes, the client, connects to the other process, the server, typically to make a request for information. A good analogy is a person who makes a phone call to another person.

The system calls for establishing a connection are somewhat different for the client and the server, but both involve the basic construct of a socket. A socket is one end of an interprocess communication channel. The two processes each establish their own socket.

Client
The basic steps involved in establishing and using a socket on the client side are as follows:

  1. Create a socket with the Socket Java class and connect the socket to the address of the server. In the DSLAB, the server runs on the local machine. That means you need to create a Socket for localhost.
  2. Send and receive data.

There are a number of ways to do this, but the simplest is to use the readLine() and write() methods of the BufferedReader and BufferedWriter classes.
Listing 1 provides sample code to do this:

Listing 1

The client should read lines from the Input Console and send each line to the server. To terminate the client the string
!end
must be entered.

Listing 2

Listing 2 provides a sample chat sequence. After each line, the client sends data to the server. If the input equals !end the client aborts communication and terminates. Be sure to release all resources and close all sockets!
Be sure to send the message according to the following format:
USERNAME [dd.MM.yyyy HH:mm:ss]: MESSAGE
Until now, we implemented a simple input system and send each line to the server. But how does a client receive our messages? For this purpose we use a Thread (let's refer to this as the ReceiverThread). The thread allocates a socket on the same host (localhost) and on the same port. It retrieves an InputStream from the Socket and a BufferedReader from this InputStream. Simply write the data read from the BufferedReader to the console.
To realize the Direct Chat functionality, we create another Thread in the Client! This thread is spawned, if we receive a direct chat request from another client. To ensure compatibility with our lab port policy we create a new listening Socket on our base port + 1 (f.e. user dslab900: 10000 + 900 * 10 => Base Port = 19000; Base Port + 1 = 19001).
This Socket accepts connections and deals with so called direct chat requests from other clients. A direct chat request establishes a direct connection from one client to another without the control of the server.

NotePlease note that this is a rather unsecure communication setting (as we are using no message encryption)!

After the listening Socket accepts a connection, a new Thread (let's refer to this as the DirectChatThread) is spawned. Every message received from the direct chat partner should be printed to the console (as the ReceiverThread does). A sample chat sequence is illustrated in Listing 3. The ReceiverThread should not print messages from the server during a Direct Chat! It is not possible to chat with other users in the direct chat mode. Only direct chat with one user (in our example: Bob) is possible! Other direct chat requests must must be rejected by sending a simple reject message.

Listing 3

The user chats with Alice by the use of the server connection. Every other client connected to the server receives these messages. Bob requests a direct chat with the user. The Client must implement this request by asking the user to accept this request. If the user accepts, a new chat sequence is initiated. To end this direct chat session, the Client awaits the input of !end. If the input equals this string, the DirectChatThread stops and the client changes into server - chat mode.

Ports This pretty basic chat scenario has a big drawback: The number of simultaneous executing clients is limited to the available port numbers. We know that, of course ;) Due to simplicity, we reduce this scenario to a maximum of four participants: 1 Server, 3 clients. During the interview with a tutor in the DSLAB, you need to present a scenario with the following setting: 1 Server running, 3 clients connected to the server. Two of them establish a direct chat and after a small chat resume to server chat mode.

Scenario 1 illustrates the server client chat mode.

Scenario 1

Server
A threaded socket-based server is probably the easiest server type to understand. A server program almost always needs to handle more than one connection at a time. The reason is, since each connection gets its own thread, each thread can use simple blocking I/O on the socket. All other multi-connection server types use non-synchronous I/O of varying complexities in order to avoid thread overhead.

Lab port policyIf your server tries to bind to a TCP port that is already listening for a connection, an exception will be thrown by your server. Because many people will be testing their servers in the lab environment, such binding errors are probable. In order to prevent this from happening, we suggest that you use your dslabXXX number when choosing a port. For example, if your dslab number is dslab900, you should use 10000 + 900 * 10 = 19000 as the server port.

To implement this functionality you need to start a Server Thread. This Thread implements an infinite loop (please refer to server stop problems in the tricky parts section for stop problems). When a client connects to the Server Socket, a new Client Thread is spawned and handles all client requests. For each connecting client the server spawns a new ClientThread. By this architecture, a clean resource handling is guaranteed. After the ClientThread was successfully started the client list needs to be updated. This list stores each client, it's address and it's port:
Userlist example for DSLAB User 456:

 UsernameHostPort
1.EntryClient01localhost14560
2.EntryClient02localhost14562
3.EntryClient03localhost14564

Every time the ClientThread receives a message, it distributes it to all currently connected clients. You need to ensure this message distribution! But before the server broadcasts every message, some simple "protocol analysis" has to be realized.
If the message matches to
!getConnectedClients
the server needs to send the list of all currently connected clients to the requesting client. Based on the information provided in this server response, clients are able to establish a direct chat connection to other participants. Be sure to send this information only to the requesting client! It is not necessary to distribute this information to all participating clients. The client receives the requested information and selects a partner for the direct chat. After that he contacts the selected direct chat partner directly. The requested chat partner receives an invitation and is asked for acceptance for a direct chat with the requester. In case of acceptance, the chat is established. Otherwise the requester receives an error message. A successful direct chat connection is traced in listing 3. The described scenario is illustrated in scenario 2.

Scenario 2

Listing 4 illustrated the direct chat partner search. [Time information is skipped for simplicity].

Listing 4

Connection Setup
The basic connection technique in this scenario is using ServerSockets and Sockets.

Client [Main application]:

  1. Reading input from a streamreader
  2. Formating Date
  3. Send the formated message to the server via a socket


ReceiverThread:

  1. Reading input from streamreader from the server
  2. Printing messages from the server to the console


DirectChatThread:

  1. Creating a ServerSocket on ports according to our port policy
  2. Ask the user for acceptance of the incoming direct chat request
  3. Spawn a new DirectChatThread for each incoming connection (in case of acceptance)


The Client Input and the DirectChatThread have to check the user input for the following two commands:
!end
This command terminates communication. If the client is currently in direct chat - mode, it resumes server chat - mode. If the client is in server chat - mode it simply terminates.
!getConnectedClients
Send a message to the server, querying for the list of all currently connected clients. The layout of the data structure can be retrieved from user list.

Test Client

Every software needs to be tested. Consequently, our DSLAB Lab 1 should be tested too. You need to implement a Test Client, using the JUnit Framework. The JUnit libraries can be found in /usr/share/ant/lib on the lab server. A pretty good introduction into the new features of JUnit 4.0 are described in JUnit 4.0 in 10 minutes. The Test Client should test the following unit tests:
1. Connect to the server
This test case should connect to the server and test simple connectivity. The test fails, when the server is not available.
2. Send sample message
In this test case, the test client connects to the server and sends some test messages. It can be tested if some messages come back, but this is not a must!
3. Request Client list
Send !getConnectedClients to the server and test the correctness of the returned user list. With the use of our provided ANT - file

Testing with junit

Tricky parts

After hours of development you compile, start your engine and...
fail! No worries, here is some advice:

Compilation problems

You cannot compile your solution. Here is some help: Use our ANT file and start by typing:
ant
This command searches for the build.xml - file and executes it.

Binding problems

After starting your socket implementation, you receive a message comparable to Error 1:

Error 1

The address and port, you are trying to bind to is already in use. To solve these issues you can test your solution at home (and don't bind to ports used by other services ;), or you simply change the ports. Our policy to use your dslab account number prevents these errors! For example: DSLAB023 = Bind to port 10230

Server stop problems

Your developed your server and implemented and infinite loop. You started it, but you cannot stop it? So, get your keyboard and do the following:

Error 2

The first line starts the server.
java {packagenames}.[serverclass] & starts the server. The ampersand (&) is important to spawn a new job in unix.
jobs lists all currently active jobs.
ps ax | grep [serverclass] retrieves the jobnumber (in the previous example 11180)
kill [jobnumber] kills the server.
Now you stopped the server and you are able to fix errors in your source code, compile and start again.

Proposed Tutorials

Java Custom Networking Tutorial
[http://java.sun.com/docs/books/tutorial/networking/index.html]
Java Sockets Tutorial
[http://java.sun.com/docs/books/tutorial/networking/sockets/index.html]
Java Concurrency Tutorial
[http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html]

Edit - History - Print - Recent Changes - Search
Page last modified on October 19, 2007, at 11:56 AM CET